<?php
/**
 * Created by PhpStorm.
 * User: hedx
 * Date: 2016/4/15
 * Time: 17:18
 */

namespace common\mq\utils;


use AliyunMNS\Queue;
use AliyunMNS\Responses\ReceiveMessageResponse;
use common\mq\models\MessageServiceModel;
use common\mq\models\MessageServiceReceiveModel;
use common\mq\models\MessageServiceSendModel;
use common\utils\DateTimeUtil;
use common\utils\DateTimeUtils;
use Yii;

class MessageHelper
{

    /**
     * 从消息主表(bizp_message_service)按优先级顺序获取指定数量的未解析消息
     *
     * @param int $size 获取记录数量
     * @return MessageServiceModel[] array 未解析的记录
     */
    public static function getUnresolvedMessageOrderByPriority($size = 50)
    {
        $unresolvedMessages = MessageServiceModel::find()->where(["resolve_status" => 0])
            ->orderBy(["message_priority" => SORT_ASC])->limit($size)->all();
        return $unresolvedMessages;
    }

    /**
     * 保存解析后的消息到消息发送表
     *
     * @param MessageServiceSendModel $messageSend
     * @return boolean
     */
    public static function saveMessageSend($messageSend)
    {
        if (empty($messageSend->message_service_id) || empty($messageSend->queue_name)) {
            Yii::error("Save messageSend failed! parameter 'message_service_id' and 'queue_name' cannot be null.");
            return false;
        }
        $messageSend->send_status = MessageServiceSendModel::NOT_SEND;
        $now = DateTimeUtils::now();
        $messageSend->send_time = $now;
        $messageSend->last_updated_time = $now;
        return $messageSend->save();
    }

    /**
     * 更新消息主表解析状态
     *
     * @param $messageServiceId
     * @param $resolveStatus
     * @param null $remark
     * @throws \Exception
     */
    public static function updateMessageResolveStatus($messageServiceId, $resolveStatus, $remark = NULL)
    {
        /** @var MessageServiceModel $message */
        $message = MessageServiceModel::find()->where(["id" => $messageServiceId])->one();
        if (!empty($message)) {
            $message->resolve_status = $resolveStatus;
            $message->last_updated_time = DateTimeUtils::now();
            if (!empty($remark)) {
                $message->remark = $remark;
            }
            $message->update();
        }
    }

    /**
     * 更新消息主表消息过程状态
     *
     * @param $messageServiceId
     * @param $messagePhase
     * @throws \Exception
     * @return int
     */
    public static function updateMessagePhase($messageServiceId, $messagePhase)
    {
        $sql = <<<sql
            UPDATE
                b2b_support.bizp_message_service
            SET
                message_phase = :messagePhase,
                last_updated_time = :now
            WHERE
                id = :id
sql;
        //防止message_phase从"已接收" => "已发送" (无法保证两种状态的更新顺序)
        if ($messagePhase == MessageServiceModel::PHASE_SENT) {
            $sql = $sql . " AND message_phase != " . MessageServiceModel::PHASE_RECEIVED;
        }

        $sqlParams = [":messagePhase" => $messagePhase, ":now" => DateTimeUtils::now(), ":id" => $messageServiceId];
        return Yii::$app->db->createCommand($sql, $sqlParams)->execute();
    }

    /**
     * 更新消息发送表的messageId
     * @param $messageServiceId
     * @param $messageId
     * @param $sendStatus
     * @return int
     * @throws \yii\db\Exception
     */
    public static function updateMessageIdForSend($messageServiceId, $messageId, $sendStatus)
    {
        $sql = <<<sql
            UPDATE
                b2b_support.bizp_message_service_send
            SET
                message_id = :messageId,
                send_status = :sendStatus,
                last_updated_time = :now
            WHERE
                message_service_id = :id
sql;
        $sqlParams = [":messageId" => $messageId, ":sendStatus" => $sendStatus, ":id" => $messageServiceId, ":now" => DateTimeUtil::now()];
        return Yii::$app->db->createCommand($sql, $sqlParams)->execute();
    }

    /**
     * 更新消息发送表状态
     * @param $messageServiceId
     * @param $sendStatus
     * @param $remark
     * @return int
     * @throws \yii\db\Exception
     */
    public static function updateMessageSendStatus($messageServiceId, $sendStatus, $remark = NULL)
    {
        $sql = <<<sql
            UPDATE
                b2b_support.bizp_message_service_send
            SET
                send_status = :sendStatus,
                last_updated_time = :now,
                remark = :remark
            WHERE
                message_service_id = :id
sql;
        $remark = mb_strlen($remark) > 180 ? mb_substr($remark, 0, 180) : $remark;
        $sqlParams = [":sendStatus" => $sendStatus, ":id" => $messageServiceId, ":remark" => $remark, ":now" => DateTimeUtil::now()];
        return Yii::$app->db->createCommand($sql, $sqlParams)->execute();
    }

    /**
     * 判断消息发送表中是否存在指定id的消息
     *
     * @param string $messageServiceId
     * @return boolean
     */
    public static function hasMessageSend($messageServiceId)
    {
        $record = MessageServiceSendModel::find()->where(["message_service_id" => $messageServiceId])->one();
        if (!empty($record)) {
            return true;
        }
        return false;
    }

    /**
     * 保存消费端接收的消息,存在则更新接收次数
     * 如果接收次数大于3次则在阿里队列中删除此消息，不再接收
     *
     * @param Queue $queue
     * @param ReceiveMessageResponse $response
     * @return boolean
     */
    public static function saveMessageReceive($queue, $response)
    {
        //需要判断消息是否被接收过
        $queueName = $queue->getQueueName();
        $messageId = $response->getMessageId();
        /** @var MessageServiceReceiveModel $receiveRecord */
        $receiveRecord = self::getMessageReceive($queueName, $messageId);
        if (empty($receiveRecord)) {
            $receive = new MessageServiceReceiveModel();
            $receive->queue_name = $queueName;
            $receive->message_id = $response->getMessageId();
            $receive->message_priority = $response->getPriority();
            $receive->message_body = $response->getMessageBody();
            $receive->is_delete = MessageServiceReceiveModel::NOT_DELETE;
            $receive->receive_times = $response->getDequeueCount();
            $now = DateTimeUtils::now();
            $receive->receive_time = $now;
            $receive->last_updated_time = $now;
            $receive->save();
        } else {
            $receiveRecord->receive_times = $response->getDequeueCount();
            $receiveRecord->update();
        }
        return true;
    }

    /**
     * 更新消息接收后的删除状态
     *
     * @param $queueName
     * @param $messageId
     * @param $deleteStatus
     * @return int
     * @throws \yii\db\Exception
     */
    public static function updateMessageReceiveDeleteStatus($queueName, $messageId, $deleteStatus)
    {
        $sql = <<<sql
            UPDATE
                b2b_support.bizp_message_service_receive
            SET
                is_delete = :deleteStatus,
                last_updated_time = :now
            WHERE
                queue_name = :queueName AND
                message_id = :messageId
sql;
        $now = DateTimeUtils::now();
        $sqlParams = [
            ":deleteStatus" => $deleteStatus,
            ":queueName" => $queueName,
            ":messageId" => $messageId,
            ":now" => $now
        ];
        return Yii::$app->db->createCommand($sql, $sqlParams)->execute();
    }

    /**
     * 获取消息接收表记录
     *
     * @param $queueName
     * @param $messageId
     * @return MessageServiceReceiveModel | null
     */
    public static function getMessageReceive($queueName, $messageId)
    {
        return MessageServiceReceiveModel::find()
            ->where(["queue_name" => $queueName, "message_id" => $messageId])
            ->one();
    }

    /**
     * 获取处于每个消息阶段的数量
     */
    public static function getMessagePhaseCount()
    {
        $sql = <<<sql
            SELECT
                message_phase AS messagePhase,
                COUNT(message_phase) AS messageCount
            FROM
                b2b_support.bizp_message_service
            GROUP BY
                message_phase;
sql;
        $results = Yii::$app->db->createCommand($sql)->queryAll();

        return MessageUtils::fillMonitorMap($results);
    }

    /**
     * 获取所有阻塞的消息(message_phase = 0 or 5)
     *
     * @return array
     */
    public static function getBlockMessages()
    {
        $sql = <<<sql
            SELECT
                id AS id,
                queue_name AS queueName
            FROM
                b2b_support.bizp_message_service
            WHERE
                message_phase = 0 OR
                message_phase = 5
sql;

        return Yii::$app->db->createCommand($sql)->queryAll();
    }

}